#include "test.h"
#include "utils.h"
#include "tentacle.h"
#include "textrender.h"
#include "drawstats.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <alloca.h>
#include <assert.h>
#include <math.h>
//#include <sys/time.h>
#include <algorithm>

#if !defined(offsetof) && !defined(_WIN32)
#define offsetof(TYPE, MEMBER)  __builtin_offsetof (TYPE, MEMBER)
#endif

#ifndef GLES2
//#include <GL/glext.h>
#endif

///////////////////////////////////////////////////////////////////////////////

Test::Test()
{
  m_textRender = NULL;
  memset(m_tentacle, 0, sizeof(m_tentacle));
  m_texture = 0;
  m_camX = 0;
  m_camY = 0;
}

Test::~Test()
{
  delete m_textRender;

  for(uint i=0; i<TENTACLES; i++)
  {
    for(uint c=0; c<TENTCLUSTER; c++)
    {
      delete m_tentacle[i][c];
    }
  }

  glDeleteTextures(1, &m_texture);
}

void Test::init()
{
  g_rand.seed(0);

  Tentacle::compileShaders();

  // texture
  glGenTextures(1, &m_texture);
  assert(m_texture > 0);
  glBindTexture(GL_TEXTURE_2D, m_texture);
  uint8_t bitmap[2][2][4] = {{{255,255,255,255}, {128,128,128,255}}, {{128,128,128,255}, {255,255,255,255}}};
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
  glGenerateMipmap(GL_TEXTURE_2D);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glBindTexture(GL_TEXTURE_2D, 0);
  assert(glGetError() == 0);

  for(uint i=0; i<TENTACLES; i++)
  {
    for(uint c=0; c<TENTCLUSTER; c++)
    {
      float height = g_rand.nextfloat(10.0f, 15.0f);
      int bones = ((g_rand.next())%40) + 5;
      bones = 15;
      m_tentacle[i][c] = new Tentacle(bones, 200, 0.2f, height, m_texture);
    }
  }

  m_textRender = new TextRender();
}

void Test::resize(int width, int height)
{
  glViewport(0, 0, width, height);
  m_projMat = mat4::makePerspectiveMat(60.0f*float(M_PI)/180.0f, float(width)/float(height), 1.0f, 250.0f);
  m_textRender->resize(width, height);
}

void Test::render()
{
  double nowtime = mtime();
  static double lasttime = nowtime;
  float deltatime = float(nowtime - lasttime);
  lasttime = nowtime;

  static float fps = 0.0f;
  if(deltatime)
    fps += (1.0f/deltatime - fps)*0.01f;

  g_drawCalls = 0;
  g_uniformCalls = 0;
  g_triangles = 0;

  glClearColor(0.2f, 0.3f, 0.4f, 1);
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);

  glFrontFace(GL_CW);
  glCullFace(GL_BACK);
  //glEnable(GL_CULL_FACE);

  g_rand.seed(0);

  uint64_t utime = uint64_t(mtime()*1000000.0);

  mat4 camMat =  mat4(vec3(0,4,0)) * mat4::makeRotateMat(m_camX, -float(M_PI)*3.0f/4.0f+m_camY, 0) * mat4(vec3(0,0,-1));
  mat4 camMatInv =  camMat.inverted();
  mat4 wpMat = m_projMat;
  for(uint i=0; i<TENTACLES; i++)
  {
    //mat4 m = mat4(vec3(7,0,7));
    mat4 m = mat4(vec3(g_rand.nextfloat(0, 150), 0, g_rand.nextfloat(0, 150)));
    for(uint c=0; c<TENTCLUSTER; c++)
    {
      m_tentacle[i][c]->draw(utime, wpMat, camMatInv, m);
    }
    //if((i&31)==31) glFlush();
  }

#if 1
  glDisable(GL_DEPTH_TEST);
  m_textRender->draw(vec2(0,2), "fps: %.2f", fps);
  //m_textRender->draw(vec2(0,3), "draw calls:    %9u", g_drawCalls);
  //m_textRender->draw(vec2(0,4), "uniform calls: %9u", g_uniformCalls);
  //m_textRender->draw(vec2(0,5), "triangles:     %9u", g_triangles);
#endif
}

void Test::mouseMoved(int deltaX, int deltaY)
{
  m_camY = std::min(std::max(m_camY-deltaX/100.0f, -2.0f), 2.0f);
  m_camX = std::min(std::max(m_camX-deltaY/100.0f, -2.0f), 2.0f);
}
